#!/usr/bin/env bash

### use demo ###
# 1)upload dump.sh
# 2)dos2unix dump.sh;chmod +x dump.sh
# 3)usage: 
#	1. /data/sh/java/dump.sh /tmp/dump /usr/local/java/jdk1.8.0_05 23554
#	2. /data/sh/java/dump.sh /tmp/dump /usr/local/java/jdk1.8.0_05 23554 -F

### parameter description ###
# 1 ./tmp/dump is save dump file dir. 
# 2 /usr/local/java/jdk1.8.0_05 is java_home. 
# 3 23554 is java-pid. 
# 4 -F force jvm dum, optional.

declare SNAPSHOT_BASE_DIRECTORY=$1
declare JAVA_HOME=$2
declare PID=$3
declare JVM_FORCE_OPTS=$4

# remove the last '/' char
JAVA_HOME=${JAVA_HOME/%\//}
SNAPSHOT_BASE_DIRECTORY=${SNAPSHOT_BASE_DIRECTORY/%\//}

declare FULL_TIME_FORMAT="+%Y-%m-%d_%H_%M_%S_%N"
declare SHORT_TIME_FORMAT="+%H-%M-%S-%N"
declare TIMESTAMP=`date ""${FULL_TIME_FORMAT}"" `
declare RESULT_DIRECTORY=${SNAPSHOT_BASE_DIRECTORY}/${PID}/${TIMESTAMP}
declare RUN_LOG_PATH="${RESULT_DIRECTORY}/run.log"

run_log(){
	declare log_msg="$(date ""${FULL_TIME_FORMAT}""): $1"
	echo ${log_msg}
	echo ${log_msg} >>${RUN_LOG_PATH}
}

is_no_null(){
	if [ -z $1 ];then
		return 0;
	else
		return 1;
	fi
}

is_valid_number(){
	is_no_null $1
	if [ $? -eq 0 ];then
		return 0;
	fi

	if [ $1 -gt 0 ] 2>/dev/null ;then
		return 1;
	else
		return 0;
	fi
}

echo_blank_line(){
	echo 
}

valid_param(){
	if [ ! -d ${RESULT_DIRECTORY} ]; then
		mkdir -p ${RESULT_DIRECTORY}
		run_log "tip: Create RESULT_DIRECTORY=${RESULT_DIRECTORY}"
	fi
	run_log "tip: RESULT_DIRECTORY=${RESULT_DIRECTORY}"

	is_no_null ${SNAPSHOT_BASE_DIRECTORY}
	if [ $? -eq 0 ];then
		run_log "Param 1 SNAPSHOT_BASE_DIRECTORY is no exist and exit ,such as /tmp/dump"
		exit 1;
	else
		run_log "tip: SNAPSHOT_BASE_DIRECTORY=${SNAPSHOT_BASE_DIRECTORY}"
	fi

	if [ -d "${JAVA_HOME}" ];then
		run_log "tip: JAVA HOME: ${JAVA_HOME}"
	else
		run_log "Param2 JAVA_HOME is no exist and exit ,such as /usr/local/java/jdk1.8.0_05"
		exit 2;
	fi

	is_valid_number ${PID}
	if [ $? -eq 0 ];then
		run_log "Param3 PID is invalid and exit"
		exit 3;
	fi
}
valid_param
run_log "RESULT_DIRECTORY=${RESULT_DIRECTORY}"

machine_dump(){
	declare filename=$1;

	type $1 >/dev/null 2>&1 && {
        	run_log "Start $1 $2 dump"
        	declare timestamp=$(date ""${SHORT_TIME_FORMAT}"");
        	run_log "Execute $1 $2 >> ${RESULT_DIRECTORY}/machine_${filename}_${timestamp}.dump"
        	$1 $2 >> ${RESULT_DIRECTORY}/machine_${filename}_${timestamp}.dump
        	run_log "End $1 $2 dump"
		echo_blank_line
	}
}

machine_dump_pipeline(){
	declare filename=$1;

	type $2 >/dev/null 2>&1 && {
		run_log "Start $2 $3 | $4 dump"
		declare timestamp=$(date ""${SHORT_TIME_FORMAT}"");
		run_log "Execute $2 $3 | $4 >> ${RESULT_DIRECTORY}/machine_${filename}_${timestamp}.dump"
		$2 $3 | $4 >> ${RESULT_DIRECTORY}/machine_${filename}_${timestamp}.dump
        	run_log "End $2 $3 | $4 dump"
		echo_blank_line
    }
}

# 3 times interval 1s
declare machine_static_frequency="1 3"

# machine real time statistics information
echo_blank_line
machine_dump_pipeline "top-50-process" top "-b" "head -n 50" 
machine_dump free -glt
machine_dump vmstat "-t ${machine_static_frequency}"
machine_dump mpstat "-A ${machine_static_frequency}"
machine_dump iostat "${machine_static_frequency}"
machine_dump iotop "-o -b -n 3"
machine_dump netstat "-an"
machine_dump lsof "-p ${PID}"
# machine history statistics information
machine_dump sar -A

get_pid_user(){
	user_tip=`ps u -p $1 | tail -n 1 | awk '{print $1}'`
	is_valid_number ${user_tip}
	if [ $? -eq 0 ];then
		echo ${user_tip}
	else
		echo `cat /etc/passwd |grep x:${user_tip} | awk -F ':' '{print $1}'`
	fi
}

PID_USER=`get_pid_user ${PID}`

jvm_dump(){
	declare filename;
	if [ ! -z $3 ];then
		filename=$3
	else
		filename=$1
	fi
	run_log "Start $1 $2 dump"
	declare timestamp=$(date ""${SHORT_TIME_FORMAT}"");
	run_log "su -l ${PID_USER} -s /bin/bash -c \"${JAVA_HOME}/bin/$1 $2 \" >>  ${RESULT_DIRECTORY}/jvm_${filename}_${timestamp}.dump"
	su -l ${PID_USER} -s /bin/bash -c "${JAVA_HOME}/bin/$1 $2 " >> ${RESULT_DIRECTORY}/jvm_${filename}_${timestamp}.dump
	run_log "End $1 $2 dump"
	echo_blank_line
}

# 8 times interval 1s
declare jvm_static_frequency="1000 8"
# jvm real time statistics information
jvm_dump jinfo "${PID}"
jvm_dump jstat "-gcutil ${PID} ${jvm_static_frequency}" "jstat-gcutil"

machine_dump_pipeline "top-100-high-thread" top "-H -b -n 1 -p  ${PID}" "head -n 100"
chown ${PID_USER}:${PID_USER} ${RESULT_DIRECTORY}
# topH have must together with jstack
jvm_dump jstack "${JVM_FORCE_OPTS} ${PID}"

# dump 
jvm_head_dump(){
	run_log "Start jmap  $1 dump"
	declare timestamp=$(date ""${SHORT_TIME_FORMAT}"");
	run_log "su -l ${PID_USER} -s /bin/bash -c \"${JAVA_HOME}/bin/jmap ${JVM_FORCE_OPTS} -dump:format=b,file=${RESULT_DIRECTORY}/jvm_jmap_${timestamp}.hprof $1\""
	su -l ${PID_USER} -s /bin/bash -c "${JAVA_HOME}/bin/jmap ${JVM_FORCE_OPTS} -dump:format=b,file=${RESULT_DIRECTORY}/jvm_jmap_${timestamp}.hprof $1" 
	run_log "End jmap $1 dump"
	echo_blank_line
}
jvm_head_dump ${PID}

# statistics all kinds of tcp status
cat ${RESULT_DIRECTORY}/machine_netstat*.dump | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' > ${RESULT_DIRECTORY}/machine_netstat_status_statistics.dump